﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum SystemProgram {
    Boot,
    Login,
    Welcome,
    Main,
    Scan,
    Move,
    Over,
    End
}

public enum OverPhase {
    Ready,
    Down
}

public enum EndPhase {
    Ready,
    Down
}

public enum MainPhase {
    Hint,
    WaitInput,
    InvaliadInput,
    InvalidInput
}

public enum BootPhase {
    Loading,
    Loaded
}

public enum LoginPhase {
    HintInputName,
    WaitName,
    Login
}

public enum MovePhase {
    Hint,
    WaitInput,
    InvalidInput
}

public class GameMgr : MonoBehaviour {
    public const float INTERVAL_TIME = 1.8f;
    public static GameMgr Ins { get; private set; }
    private float interval = INTERVAL_TIME;
    private SystemProgram currProgram = SystemProgram.Boot;
    private BootPhase currBootPhase = BootPhase.Loading;
    private LoginPhase currLoginPhase = LoginPhase.HintInputName;
    private MainPhase currMainPhase = MainPhase.Hint;
    private MovePhase currMovePhase = MovePhase.Hint;
    private int loginWaitTicks = 10;
    [SerializeField]
    private GameConfigClass gameConfig;
    [SerializeField]
    private JournalClass journal;
    [SerializeField]
    private AudioSource audioSource;

    private void Awake() {
        Ins = this;
    }

    // Use this for initialization
    void Start () {
	}
	
	// Update is called once per frame
	void Update () {
        NextTick();
	}

    private void NextTick() {
        interval -= Time.deltaTime;
        if (interval <= 0) {
            ProcessProgram();
            interval = INTERVAL_TIME;
        }
    }

    private void ProcessProgram() {
        switch(currProgram) {
            case SystemProgram.Boot:
            if(ProcessBoot()) {
                currProgram = SystemProgram.Login;
            }
            break;
            case SystemProgram.Login:
            if(ProcessLogin()) {
                currProgram = SystemProgram.Welcome;
            }
            break;
            case SystemProgram.Welcome:
            TernimalPanel.Ins.AppendLine(gameConfig.cfg.wlcMsg);
            currProgram = SystemProgram.Main;
            UnlockJournal(0);
            break;
            case SystemProgram.Main:
            ProcessMain();
            break;
            case SystemProgram.Move:
            ProcessMove();
            break;
        }
    }

    private DataPoint[] locationArray;
    private void ProcessMove() {
        switch(currMovePhase) {
            case MovePhase.Hint:
            TernimalPanel.Ins.AppendLine("请输入你要前往的地点");
            string hintStr = string.Empty;
            var currEntryMap = Player.Ins.currentPoint.entryMap;
            locationArray = new DataPoint[currEntryMap.Length];

            for(int i = 0; i < currEntryMap.Length; i++) {
                var entry = currEntryMap[i];
                locationArray[i] = entry;
                if (!locationArray[i].discovered) {
                    hintStr += i + ": " + locationArray[i].pointName + "（未扫描）" + Coord(locationArray[i]) + "\n";
                } else {
                    hintStr += i + ": " + locationArray[i].pointName + " " + Coord(locationArray[i]) + "\n";
                }
            }

            hintStr += "x: 停止跃迁程序\n";

            TernimalPanel.Ins.AppendLine(hintStr);
            currMovePhase = MovePhase.WaitInput;
            break;
            case MovePhase.WaitInput:
            break;
            case MovePhase.InvalidInput:
            TernimalPanel.Ins.AppendLine("地点输入错误！");
            currMovePhase = MovePhase.WaitInput;
            break;
        }
    }

    private string Coord(DataPoint point) {
        return string.Format("x：{0}, y：{1}, z：{2}",
            point.transform.position.x,
            point.transform.position.y,
            point.transform.position.z
        );
    }


    private List<int> unlockedJournal = new List<int>();
    private string journalLog = String.Empty;
    private void UnlockJournal(int ID) {
        if(!unlockedJournal.Exists(n => n == ID)) {
            TernimalPanel.Ins.AppendLine("*** 航行日志已更新 ***\n");
            journalLog += "===========================================\n" + journal.journals[ID].content + "\n";
            unlockedJournal.Add(ID);
        }
    }

    private bool ProcessMain() {
        switch(currMainPhase) {
            case MainPhase.Hint:
            TernimalPanel.Ins.AppendLine("\n" + gameConfig.cfg.mainMsg);
            currMainPhase = MainPhase.WaitInput;
            break;
            case MainPhase.WaitInput:
            break;
            case MainPhase.InvalidInput:
            TernimalPanel.Ins.AppendLine("指令输入错误！\n");
            currMainPhase = MainPhase.WaitInput;
            break;
        }
        return false;
    }

    private bool ProcessBoot() {
        switch(currBootPhase) {
            case BootPhase.Loading:
            TernimalPanel.Ins.AppendText("Initialization System...");
            InitConfig();
            currBootPhase = BootPhase.Loaded;
            break;
            case BootPhase.Loaded:
            TernimalPanel.Ins.AppendLine("System Language : Chinese\n系统初始化成功！");
            return true;
        }
        return false;
    }

    private bool ProcessLogin() {
        switch(currLoginPhase) {
            case LoginPhase.HintInputName:
            TernimalPanel.Ins.AppendLine("用户名:");
            currLoginPhase = LoginPhase.WaitName;
            break;
            case LoginPhase.WaitName:
            if((loginWaitTicks--) < 0) {
                TernimalPanel.Ins.AppendText(" " + gameConfig.cfg.usr);
                TernimalPanel.Ins.AppendLine("密码: ******");
                currLoginPhase = LoginPhase.Login;
            }
            break;
            case LoginPhase.Login:
            TernimalPanel.Ins.AppendLine("正在登陆系统(192.168.1.1)...\n系统登录成功！");
            return true;
        }
        return false;
    }

    public void OnCommandInput(string text) {
        if(currProgram == SystemProgram.Login &&
            currLoginPhase == LoginPhase.WaitName &&
            text.Length > 0) {
            gameConfig.cfg.usr = text;
            loginWaitTicks = -1;
        }
        if(currProgram == SystemProgram.Main &&
            currMainPhase == MainPhase.WaitInput &&
            text.Length > 0) {
            switch(text) {
                case "m":
                currProgram = SystemProgram.Move;
                currMovePhase = MovePhase.Hint;
                break;
                case "s":
                if(Player.Ins.currentPoint.Discovery()) {
                    TernimalPanel.Ins.AppendLine("扫描完成\n");
                }
                break;
                case "o":
                if(!Player.Ins.currentPoint.discovered) {
                    TernimalPanel.Ins.AppendLine("地点尚未扫描，无法启动打捞程序\n");
                    return;
                }
                bool result = Player.Ins.currentPoint.Scan();
                if(result) {
                    TernimalPanel.Ins.AppendLine("打捞完成\n");
                } else {
                    TernimalPanel.Ins.AppendLine("已完全打捞\n");
                }
                break;
                case "j":
                TernimalPanel.Ins.AppendLine("▇▇▇▇▇ 航行日志 ▇▇▇▇▇\n" + journalLog);
                break;
                case "q":
                Application.Quit();
                break;
                default:
                currMainPhase = MainPhase.InvalidInput;
                break;
            }
        }

        if(currProgram == SystemProgram.Move &&
            currMovePhase == MovePhase.WaitInput &&
            text.Length > 0) {
            if(text == "x") {
                currProgram = SystemProgram.Main;
                currMainPhase = MainPhase.WaitInput;
                TernimalPanel.Ins.AppendLine("跃迁程序已停止\n");
                return;
            }
            int number;
            bool result = int.TryParse(text, out number);
            if(!result) {
                currMovePhase = MovePhase.InvalidInput;
                return;
            }
            if(number >= locationArray.Length || number < 0) {
                currMovePhase = MovePhase.InvalidInput;
            } else {
                // TODO: check item
                if(locationArray[number].type == 3 || locationArray[number].type == 2) {
                    if(!Player.Ins.inventory.Exists(n => n == 3)) {
                        TernimalPanel.Ins.AppendLine("通信模块被干扰，无法准确定位目的地\n");
                        return;
                    }
                }
                Player.Ins.target = locationArray[number];
                TernimalPanel.Ins.AppendLine("即将跃迁至目的地：" + locationArray[number].pointName);
                audioSource.Play();
                locationArray = null;
            }
        }
    }

    private void InitConfig() {
    }

    public void FinishMove() {
        currProgram = SystemProgram.Main;
        currMainPhase = MainPhase.Hint;
        TernimalPanel.Ins.AppendLine("跃迁程序已停止\n");
        if(Player.Ins.currentPoint.type == 1) {
            TernimalPanel.Ins.AppendLine("你进入了虫洞，本系统尚未被设计于虫洞航行！\n");
            GameOver();
        }
    }

    public void GameOver() {
        currProgram = SystemProgram.Over;
    }
}
